home *** CD-ROM | disk | FTP | other *** search
- ///-*-C++-*-//////////////////////////////////////////////////////////////////
- //
- // Hoard: A Fast, Scalable, and Memory-Efficient Allocator
- // for Shared-Memory Multiprocessors
- // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
- //
- // Copyright (c) 1998-2000, The University of Texas at Austin.
- //
- // This library is free software; you can redistribute it and/or modify
- // it under the terms of the GNU Library General Public License as
- // published by the Free Software Foundation, http://www.fsf.org.
- //
- // This library is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- //
- //////////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////////////
- //
- // Note: This file was modified by Crystal Decisions in June 2002.
- //
- //////////////////////////////////////////////////////////////////////////////
-
- #ifdef WIN32
-
- #include <assert.h>
-
- #include "arch-specific.h"
-
- // How many iterations we spin waiting for a lock.
- enum
- {
- SPIN_LIMIT = 100, // user lock
- SPIN_LIMIT_S = 16 // system lock
- };
-
- static SYSTEM_INFO si;
- static DWORD numberOfProcessors = 1;
- static int unusedBits = 0;
- static DWORD flVirtualAlloc = MEM_COMMIT;
-
- // TryEnterCriticalSection
- typedef BOOL (WINAPI *PROC_TryEnterCriticalSection)(LPCRITICAL_SECTION lpcs);
- static PROC_TryEnterCriticalSection ptrTryEnterCriticalSection = NULL;
-
- // SwitchToThread
- typedef BOOL (WINAPI *PROC_SwitchToThread)();
- static PROC_SwitchToThread ptrSwitchToThread = NULL;
-
- static int initSystemInfo()
- {
- // si and numberOfProcessors
- GetSystemInfo(&si);
- numberOfProcessors = si.dwNumberOfProcessors;
-
- OSVERSIONINFO versionInfo;
- versionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
- ::GetVersionEx( &versionInfo );
-
- // unusedBits
- if ((versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
- (versionInfo.dwMajorVersion >= 5)) //Windows 2000
- {
- unusedBits = 2; //The thread ID on Windows 2000 is always a multiple of 4.
- }
- else
- unusedBits = 0;
-
- // ptrTryEnterCriticalSection
- if ((versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
- (versionInfo.dwMajorVersion >= 4)) //Windows NT 4 or later
- {
- HMODULE hModule = ::GetModuleHandleA("KERNEL32.DLL");
-
- ptrTryEnterCriticalSection = (PROC_TryEnterCriticalSection)::GetProcAddress(hModule, "TryEnterCriticalSection");
- ptrSwitchToThread = (PROC_SwitchToThread)::GetProcAddress(hModule, "SwitchToThread");
- }
-
- // flVirtualAlloc
- if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
- flVirtualAlloc = MEM_COMMIT | MEM_TOP_DOWN;
- else
- flVirtualAlloc = MEM_COMMIT;
-
- return 1;
- }
-
- static const int blInitialized = initSystemInfo();
-
- int hoardGetPageSize (void)
- {
- return (int) (si.dwPageSize);
- }
-
- int hoardGetNumProcessors (void)
- {
- return numberOfProcessors;
- }
-
- int hoardGetThreadID (void)
- {
- int tid = GetCurrentThreadId() >> unusedBits;
- return tid;
- }
-
- unsigned long hoardInterlockedExchange (unsigned long * oldval,
- unsigned long newval)
- {
- return InterlockedExchange ((long *) oldval, newval);
- }
-
- void hoardCreateThread (hoardThreadType& t,
- void *(*function) (void *),
- void * arg)
- {
- t = CreateThread (0, 0, (LPTHREAD_START_ROUTINE) function, (LPVOID) arg, 0, 0);
- }
-
- void hoardJoinThread (hoardThreadType& t)
- {
- WaitForSingleObject (t, INFINITE);
- }
-
- void hoardSetConcurrency (int)
- {
- }
-
- // hoardLockType
- void hoardLockInit (hoardLockType& mutex)
- {
- InterlockedExchange (&mutex, 0);
- }
-
- void hoardLock (hoardLockType& mutex)
- {
- // A yielding lock (with an initial spin).
- int i;
- while (1)
- {
- i = 0;
- while (i < SPIN_LIMIT)
- {
- if (mutex != LOCKED)
- {
- if (InterlockedExchange (&mutex, LOCKED) == UNLOCKED)
- {
- // We got the lock.
- return;
- }
- }
- i++;
- }
-
- // Yield to other threads.
- if (ptrSwitchToThread != NULL)
- ptrSwitchToThread();
- else
- Sleep(0);
- }
- }
-
- void hoardUnlock (hoardLockType& mutex)
- {
- InterlockedExchange (&mutex, UNLOCKED);
- }
-
- // hoardLockTypeS
- void hoardLockInit (hoardLockTypeS& mutex)
- {
- ::InitializeCriticalSection(&mutex);
- }
-
- void hoardLock (hoardLockTypeS& mutex)
- {
- if (numberOfProcessors > 1)
- {
- int i = 0;
- while (i < SPIN_LIMIT_S)
- {
- if (ptrTryEnterCriticalSection(&mutex)) // We got the lock.
- return;
- i++;
- }
- }
-
- // Yield to other threads.
- ::EnterCriticalSection( &mutex );
- }
-
- void hoardUnlock (hoardLockTypeS& mutex)
- {
- ::LeaveCriticalSection( &mutex );
- }
-
- void hoardYield (void)
- {
- if (ptrSwitchToThread != NULL)
- ptrSwitchToThread();
- else
- Sleep(0);
- }
-
- // I could possibly reduce the size of the following array to 8K, but then I have to add a
- // lock or something to synchronize the access.
- static unsigned char segmentMasks[ 65536 ];
- inline void markSegment( void* ptr, long size, unsigned char flag )
- {
- assert( ( ( DWORD )ptr & 0xffff ) == 0 );
- int index = ( ( DWORD )ptr >> 16 );
- do
- {
- segmentMasks[ index ] = flag;
- size -= 65536;
- if ( size <= 0 )
- break;
- index ++;
- } while ( 1 );
- }
-
- bool hoardIsHoardPtr( void* ptr )
- {
- int index = ( ( DWORD )ptr >> 16 );
- return( segmentMasks[ index ] == 1 );
- }
-
- void * hoardSbrk (long size)
- {
- void * newMemory = ::VirtualAlloc (NULL, size, flVirtualAlloc, PAGE_READWRITE);
- assert (newMemory);
-
- markSegment( newMemory, size, 1 );
- return newMemory;
- }
-
- void hoardUnsbrk (void * ptr, long size)
- {
- markSegment( ptr, size, 0 );
-
- BOOL bResult = ::VirtualFree (ptr, 0, MEM_RELEASE);
- assert (bResult);
- }
-
- #endif // WIN32
-